/*
 * This file is a part of the SWFer project.
 *
 * Copyright (C) 2012 Michael Bradshaw <mjbshaw@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include "ByteWriter.hpp"

namespace swfer
{

ByteWriter::ByteWriter(std::ostream& stream) : stream(stream)
{
}

void ByteWriter::write(char value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 1);
}

void ByteWriter::write(int8_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 1);
}

void ByteWriter::write(int16_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 2);
}

void ByteWriter::write(int32_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 4);
}

void ByteWriter::write(uint8_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 1);
}

void ByteWriter::write(uint16_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 2);
}

void ByteWriter::write(uint32_t value)
{
	flushBitField();
    stream.write(reinterpret_cast<const char*>(&value), 4);
}

void ByteWriter::write(const Rect& value)
{
	flushBitField();
    write(value.bits);
    write(value.xMin);
    write(value.xMax);
    write(value.yMin);
    write(value.yMax);
}

void ByteWriter::write(const Fixed16& value)
{
    write(value.fraction);
    write(value.integer);
}

void ByteWriter::write(const Fixed32& value)
{
    write(value.fraction);
    write(value.integer);
}

void ByteWriter::write(const TagHeader& value)
{
	uint16_t tmp = (value.code << 6) | (value.length >= 0x3f ? 0x3f : value.length);
    write(tmp);

    if (value.length >= 0x3f)
    {
        write(value.length);
    }
}

void ByteWriter::write(const SwfHeader& value)
{
    // TODO: allow manipulation of the header? (and compression?)
    write('F');
    write('W');
    write('S');

    write(value.version);
    write(value.fileLength);
    write(value.frameSize);
    write(value.frameRate);
    write(value.frameCount);
}

void ByteWriter::write(const Packet& value)
{
	write(value.header);
	write(value.data);
}

void ByteWriter::write(const std::string& value)
{
	flushBitField();
	stream.write(value.c_str(), value.size() + 1);
}

void ByteWriter::write(const std::vector<char>& value)
{
	flushBitField();
	stream.write(value.data(), value.size());
}

void ByteWriter::flushBitField()
{
	while (bitField.size() >= 8)
	{
		char c = 0;
		for (int shift = 7; shift >= 0; --shift)
		{
			c |= bitField.front() << shift;
			bitField.pop_front();
		}
		stream.put(c);
	}

	if (bitField.size() > 0)
	{
		char c = 0;
		int shift = 7;
		while (bitField.size() > 0)
		{
			c |= bitField.front() << shift--;
			bitField.pop_front();
		}
		stream.put(c);
	}
}

}